#ifndef T_AUTOMA_MODULES_COMMS_INTERFACE_HPP
#define T_AUTOMA_MODULES_COMMS_INTERFACE_HPP

#include<vector>
#include<string>
#include "SerialPortManager/HandShake.hpp"

typedef void(__stdcall* CommDataCallbackMP)(int index, bool success, const void* log, int logLen, const void* data, int dataLen);
typedef void(__stdcall* CommDataCallback)(bool success, const void* log, int logLen, const void* data, int dataLen);

struct CommsInterface {
	static std::string ClassHint;
	static bool flagSimu;
	// need seperate groups
	static void setSimuMode(bool newFlag);
	// initialize list of possible COM ports
	static void* searchForSlavesOverSerial(bool simuThis, std::vector<std::wstring> hardwareIds,
		int baudRate, int parity, int dataBitNum, int stopBitNum, HandShakeProtocol& handshake);

	// initialize list of possible COM ports
	static void searchForSlavesOverEthernet(std::vector<std::vector<uint8_t>>& hardwareIds);
	// get next COM the matches any hardwareId
	static void* discoverNextOverEthernet();

	static int pendingPortCBRefIdx;
	static CommDataCallbackMP pendingPortSentCB;
	static CommDataCallbackMP pendingPortReceiveCB;
};

/*
* Used by slave manager as abstract comm channel
* Establishing connection (with explicit manager type) is done outside
only with the manager set here
*/
struct CommChannel {
public:
	void setSimu();
	bool isSimu();

	virtual void setManager(void* managerPtr) {};
	virtual std::string getHardware() { return ""; };
	virtual std::string toStr() { return ""; };
	virtual int isConnected() { return -1; };
	virtual int sendSignal(std::string signalName, int signalVal) { return -1; };
	virtual int sendBytes(std::vector<uint8_t> bytes) { return -1; };
	virtual int sendString(std::string str) { return -1; };
	virtual 	std::string receiveStrReplyWithDelim(int timeoutMs, char delim) { return ""; };
	//std::vector<uint8_t> receiveReplyWithLen(int timeoutMs);
	virtual void purge() {};
	virtual int reconnect() { return -1; };
	virtual 	int disconnect() { return -1; };

	//virtual int setCB(CommDataCallback sentCB, CommDataCallback receiveCB) { return -1; };
	virtual int setMPCB(int mpIndex, CommDataCallbackMP sentCB, CommDataCallbackMP receiveCB) { return -1; };

	virtual int executeHandshake(HandShakeProtocol& handshake, int softTimeout) { return 0; };

	static CommChannel* shallowCopy(CommChannel* ref);

	virtual std::string getInterfaceType() { return "virtual"; }
private:
	bool flagSimu = false;
};

struct CommChannelSerial :public CommChannel {
	struct CommNative {
		~CommNative();
		void* serialManager = nullptr;
		//int isReference = 0;
	}_commNat;

	void setManager(void* managerPtr);
	// not meaningful for now, as no sharing happen really. sharead channel take place at TBridge
	void shareManager(CommChannelSerial* channel);
	std::string getHardware();
	std::string toStr();
	int isConnected();
	int sendSignal(std::string signalName, int signalVal);
	int sendBytes(std::vector<uint8_t> bytes);
	int sendString(std::string str);
	std::string receiveStrReplyWithDelim(int timeoutMs, char delim);
	//std::vector<uint8_t> receiveReplyWithLen(int timeoutMs);
	void purge();
	int reconnect();
	int disconnect();

	//int setCB(CommDataCallback sentCB, CommDataCallback receiveCB);
	int setMPCB(int mpIndex, CommDataCallbackMP sentCB, CommDataCallbackMP receiveCB);

	int executeHandshake(HandShakeProtocol& handshake, int softTimeout);

	static int executeHandshake(void* serialManager, HandShakeProtocol& handshake, int softTimeout);
	std::string getInterfaceType() { return "serial"; }
	static void prepare();
private:
};

struct CommChannelEthernet :public CommChannel {
	void* ethernetManager = nullptr;
	std::string getInterfaceType() { return "ethernet"; };
private:
};

struct HardwareList {
	static std::vector<std::wstring> getSerialHWIDs();
};

#endif